package tcp

import (
	"crypto/tls"
	"encoding/hex"
	"log"
	"net"

	"github.com/plgd-dev/go-coap/v3/message/pool"
)

var dataMaxLen int = 4096

// TCP server
type Server struct {
	address string // Address to open connection: localhost:9999
	config  *tls.Config
	handle  IHandle
	Manager IManager
	// onNewClientCallback      func(c *Client)
	onClientConnectionClosed func(c *Client, err error)
	onNewMessage             func(c *Client, req *pool.Message)
}

// Called right after server starts listening new client
func (s *Server) onNewClient(c *Client) {
	s.Manager.Add(c)
	log.Printf("new Client id:%s\n", c.GetId())
	hellB, _ := hex.DecodeString("50e12380010020")
	c.SendBytes(hellB)
}

// Called right after connection closed
func (s *Server) OnClientConnectionClosed(callback func(c *Client, err error)) {
	s.onClientConnectionClosed = callback
}

// Called when Client receives new message
func (s *Server) OnNewMessage(c *Client, req *pool.Message) {
	//s.onNewMessage = callback
	s.handle.DoMsgHandler(c, req)
}

func (s *Server) AddRouter(pattern string, hFunc HandlerFunc) {
	s.handle.AddRouter(pattern, hFunc)
}

// Listen starts network server
func (s *Server) Listen() {
	var listener net.Listener
	var err error
	if s.config == nil {
		listener, err = net.Listen("tcp", s.address)
	} else {
		listener, err = tls.Listen("tcp", s.address, s.config)
	}
	if err != nil {
		log.Fatal("Error starting TCP server.\r\n", err)
	}
	defer listener.Close()

	for {
		conn, _ := listener.Accept()

		client := &Client{
			id:     conn.RemoteAddr().String(),
			conn:   conn,
			Server: s,
		}
		go client.listen()
	}
}

func (s *Server) GetManager() IManager {
	return s.Manager
}

// Creates new tcp server instance
func New(address string) *Server {
	log.Println("Creating server with address", address)
	server := &Server{
		address: address,
		handle:  NewMsgHandle(),
		Manager: NewManager(),
	}

	//server.OnNewClient(func(c *Client) {})
	// server.OnNewMessage(func(c *Client, req *pool.Message) {
	// 	server.handle.DoMsgHandler(c, req)
	// })
	server.OnClientConnectionClosed(func(c *Client, err error) {})

	return server
}

func NewWithTLS(address, certFile, keyFile string) *Server {
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		log.Fatal("Error loading certificate files. Unable to create TCP server with TLS functionality.\r\n", err)
	}
	config := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}
	server := New(address)
	server.config = config
	return server
}
